package com.networklib;

import android.util.LruCache;

import com.networklib.task.base.ATask;
import com.networklib.task.exception.TaskException;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import timber.log.Timber;

/**
 * Created by ASUS on 2017/6/13.
 */

public class ThreadPoolUtil {
    private Map<String, Future<TaskResult>> mTaskResultFutrue;
    private LruCache<String, ATask> mTaskContent;

    private static ThreadPoolUtil mThreadPoolUtil = null;
    private ExecutorService mExecutorService;

    private ThreadPoolUtil(Builder builder) {
        mTaskResultFutrue = new HashMap<>();
        this.mTaskContent = new LruCache<>(80);
        ArrayBlockingQueue queue = new ArrayBlockingQueue(100);
        this.mExecutorService = new ThreadPoolExecutor(builder.mCorePoolSize, builder.mMaximumPoolSize, builder.mKeepAliveTime, builder.mTimeUnit, queue);
        if (builder.mAwaitTerminationTime > 0L) {
            try {
                this.mExecutorService.awaitTermination(builder.mAwaitTerminationTime, builder.mTimeUnit);
            } catch (InterruptedException var4) {
                Timber.d("mAwaitTerminationTime 线程超时或被中断");
            }
        }
    }

    public static ThreadPoolUtil getInstance() {
        if (mThreadPoolUtil == null) {
            synchronized (ThreadPoolUtil.class) {
                if (mThreadPoolUtil == null) {
                    mThreadPoolUtil = new ThreadPoolUtil(new Builder());
                }
            }
        }
        return mThreadPoolUtil;
    }

    public void excute(ATask aTask) {
        Future<TaskResult> taskResultFuture = mExecutorService.submit(aTask);
        mTaskContent.put(aTask.getTag(), aTask);
        this.mTaskResultFutrue.put(aTask.getTag(), taskResultFuture);
    }

    public void cancel(ATask aTask) throws TaskException {
        String taskTag = aTask.getTag();
        try {
            Future e = (Future)this.mTaskResultFutrue.get(taskTag);
            if(e != null) {
                if(e.isDone()) {
                    Timber.e("任务%s已经完成，不能取消.任务执行结果为==>>%s", new Object[]{taskTag, ((TaskResult)e.get()).getResultCode().toString()});
                    this.mTaskResultFutrue.remove(taskTag);
                    this.mTaskContent.remove(taskTag);
                    return;
                }

                e.cancel(true);
                this.mTaskResultFutrue.remove(taskTag);
                this.mTaskContent.remove(taskTag);
                Timber.d("任务%s已取消", new Object[]{taskTag});
            } else {
                Timber.e("任务%s未添加执行或已移除...", new Object[]{taskTag});
            }

        } catch (Exception var3) {
            throw new TaskException(var3);
        }
    }

    public static class Builder {
        private int mCorePoolSize = 3;
        private int mMaximumPoolSize = 30;
        private TimeUnit mTimeUnit;
        private long mKeepAliveTime;
        private long mAwaitTerminationTime;

        public Builder() {
            this.mTimeUnit = TimeUnit.SECONDS;
            this.mKeepAliveTime = 120L;
            this.mAwaitTerminationTime = 0L;
        }

        public ThreadPoolUtil.Builder setCorePoolSize(int corePoolSize) {
            this.mCorePoolSize = corePoolSize;
            return this;
        }

        public ThreadPoolUtil.Builder setMaximumPoolSize(int maximumPoolSize) {
            this.mMaximumPoolSize = maximumPoolSize;
            return this;
        }

        public ThreadPoolUtil.Builder setKeepAliveTime(long keepAliveTime) {
            this.mKeepAliveTime = keepAliveTime;
            return this;
        }

        public ThreadPoolUtil.Builder setTimeUnit(TimeUnit timeUnit) {
            this.mTimeUnit = timeUnit;
            return this;
        }

        public ThreadPoolUtil.Builder setAwaitTerminationTime(long awaitTerminationTime) {
            this.mAwaitTerminationTime = awaitTerminationTime;
            return this;
        }

        public ThreadPoolUtil build() {
            ThreadPoolUtil.mThreadPoolUtil = new ThreadPoolUtil(this);
            return ThreadPoolUtil.mThreadPoolUtil;
        }
    }
}
